# This PowerShell script was released under the Ms-PL license
# http://www.opensource.org/licenses/ms-pl.html
# This script was originally intended for use with Microsoft Dynamics AX 2009
# and maintained and distributed as a project on CodePlex
# http://dynamicsaxbuild.codeplex.com 

param(
	[string] $SOURCEPATH = $(throw "XPO Source Path Required"),
	[string] $BINARIESPATH = $(throw "Binary Output Path Required"),
	[string] $BUILDNUMBER = $(throw "Build number required"),
	[string] $AXCONFIGPATH = $(throw "AX Configuration File Required"),
	[string] $LAYERSTOCLEAN = "",
	[long] $AXIMPORTTIMEOUT = 300000,
	[long] $AXSYNCTIMEOUT = 600000,
	[long] $AXCOMPILETIMEOUT = 5400000
	)

if(!(Test-Path $SOURCEPATH))
{
	Throw ("Error: Source path " + $SOURCEPATH + "does not exist")
}
if(!(Test-Path $BINARIESPATH))
{
	Throw ("Error: Binaries path " + $BINARIESPATH + "does not exist")
}
if(!(Test-Path $AXCONFIGPATH))
{
	Throw ("Error: Could not find configuration file " + $AXCONFIGPATH)
}

# ********************************************
# ** Get Information From AOS Configuration **
# ********************************************

# Get the client bin directory from the config file
$axClientPath = [string] (type $AXCONFIGPATH | Select-String "bindir")
$axClientPath = ($axClientPath.split(","))[2]

# Get the server name from the config file
$aosServer = [string] (type $AXCONFIGPATH | Select-String "aos2")
$aosServer = ($aosServer.split(","))[2]
$aosServer = ($aosServer.split("@"))[1]
$aosServer = ($aosServer.split(":"))[0]

# Make sure we're on the right server
if ($aosServer -ne (gc env:computername))
{
	Throw "Error: Script must be run on the AOS server the config file points to"
}

# Get the layer and layercode from the configuration
$buildlayer = [string] (type $AXCONFIGPATH | Select-String "aol,")
$buildlayer = ($buildlayer.split(","))[2]
$buildlayerCode = [string] (type $AXCONFIGPATH | Select-String "aolcode,")
$buildlayerCode = ($buildlayerCode.split(","))[2]

if($buildLayerCode -eq $null -or $buildLayerCode -eq "")
{
	Throw ("No layer code specified for build layer " + $buildlayer)
}

# Get the log path
$logPath = [string] (type $AXCONFIGPATH | Select-String "logDir")
$logPath = ($logPath.split(","))[2]

# Get the AOS port from the configuration (aos name is ignored when connecting, so port is the only valid identifier)
$aosPort = [string] (type $AXCONFIGPATH | Select-String "aos2")
$aosPort = ($aosPort.split(","))[2]
$aosPort = ($aosPort.split(":"))[1]

# Open the list of servers running on this machine
$aosRegistryPath = "hklm:`\SYSTEM`\CurrentControlSet`\services`\Dynamics Server`\5.0"
$aosServers = Get-Item $aosRegistryPath
$aosServers = $aosServers.GetSubKeyNames()
$aosService = ""
for ($i=0; $i -le ($aosServers.Length - 1); $i++)
{
# Get the server properties, to find the current active config
	$serverProperties = Get-ItemProperty ($aosRegistryPath + "`\" + $aosServers[$i])
# Get the configuration
	$serverConfiguration = Get-ItemProperty ($aosRegistryPath + "`\" + $aosServers[$i] + "`\" + $serverProperties.Current)
# If this is our AOS port, get out of the loop
	if ($serverConfiguration.port -eq $aosPort)
	{
		$aosService = "AOS50`$" + $aosServers[$i]
		break
	}
	$aosService = ""
}

# If we didn't find it, throw an error
if ($aosService -eq "")
{
	Throw "Error: Could not find configuration for server running on port " + $aosPort
}

# Verify the layer we're building has a directory in the source path
# Since source control is with IDs, this is important

# Check if our layer directory exist
$buildSourcePath = $SOURCEPATH
if((Test-Path ($SOURCEPATH + "`\" + $buildLayer)))
{
# If so, point the source path there
	$SOURCEPATH = ($SOURCEPATH + "`\" + $buildLayer)
}
# If it didn't exist, check if we're building for a patch layer
elseif(($buildLayer[2].ToUpper())[2] -eq "P")
{
# If we're building a patch layer, check the original layer
	switch($buildLayer.ToUpper())
	{
		"SYP" { $originalLayer = "sys" }
		"GLP" { $originalLayer = "gls" }
		"BUP" { $originalLayer = "bus" }
		"VAP" { $originalLayer = "var" }
		"CUP" { $originalLayer = "cus" }
		"USP" { $originalLayer = "usr" }
		default { Throw ("Error: unknown patch layer") }
	}

# Check if there's a directory for that original layer
	if((Test-Path ($SOURCEPATH + "`\" + $originalLayer)))
	{
# If so, point the source path there
		$SOURCEPATH = ($SOURCEPATH + "`\" + $originalLayer)
	}
	else
	{	
		Throw ("Error: No directory for layer " + $buildLayer + " or layer " +  $originalLayer + " was found in the source directory")
	}
}
else
{	
	Throw ("Error: No directory for layer " + $buildLayer + " was found in the source directory")
}

# ********************************************
# **              Combine XPOs              **
# ********************************************
$xpoPath = ($buildSourcePath) + "`\" + ($BUILDNUMBER + ".xpo")
& ($buildSourcePath + "`\CombineXPOs.ps1") ($SOURCEPATH) ($buildSourcePath) ($BUILDNUMBER + ".xpo") ($BUILDNUMBER)

# Get the application folder path
$applicationPath = $serverConfiguration.directory + "`\Appl\" + $serverConfiguration.application + "`\"

# ********************************************
# **      Stop the AOS if it's running      **
# ********************************************

"Stopping the AOS..."

# Query the service for status
$aosService = Get-Service $aosService
if ($aosService.Status -eq "Running")
{
# If it's running, stop the service
	Stop-Service -WarningAction:SilentlyContinue $aosService.Name
}
# Refresh our object
$aosService.Refresh()
if ($aosService.Status -eq "Running")
{
# If it's still running, something's wrong!
	Throw "Error: AOS service still running"
}

# ********************************************
# **             Clean the AOS              **
# ********************************************

"Cleaning up the AOS layers and indexes..."

# Clean the AOS: delete layers, remove indexes
& ($buildSourcePath + "`\CleanAOS.ps1") $aosService $applicationPath $buildSourcePath $buildLayer $LAYERSTOCLEAN $logPath

# ********************************************
# ** Copy the labels into the application directory **
# ********************************************

# Copy labels to the application path
& ($buildSourcePath + "`\CopyLabels.ps1") ($buildSourcePath + "`\labels") $applicationPath

# ********************************************
# **             Start the AOS              **
# ********************************************

"Starting the AOS..."

# Start the AOS service
Start-Service -WarningAction:SilentlyContinue $aosService.Name

# Refresh our object
$aosService.Refresh()
if ($aosService.Status -ne "Running")
{
# If it's not running, something's wrong!
	Throw "Error: AOS service could not be started"
}

# ********************************************
# **       Import the Combined XPO          **
# ********************************************

$params = "`"" + $AXCONFIGPATH + "`" -lazyclassloading -lazytableloading -minimize"

$host.SetShouldExit(0)
"Importing combined XPO..."
$axProcess = Start-Process -PassThru ($axClientPath + "`\Ax32.exe") -WindowStyle minimized -ArgumentList ($params + " `"-AOTIMPORTFILE=" + $xpoPath + "`" -nocompileonimport")
if ($axProcess.WaitForExit($AXIMPORTTIMEOUT) -eq $false)
{
	Throw ("Error: Import did not complete within " + $AXIMPORTTIMEOUT / 60000 + " minutes")
}
"Synchronizing database..."
$axProcess = Start-Process -PassThru ($axClientPath + "`\Ax32.exe") -WindowStyle minimized -ArgumentList ($params + " -StartupCmd=Synchronize")
if ($axProcess.WaitForExit($AXSYNCTIMEOUT) -eq $false)
{
	Throw ("Error: Synchronize did not complete within " + $AXSYNCTIMEOUT / 60000 + " minutes")
}
"Compiling application..."
$axProcess = Start-Process -PassThru ($axClientPath + "`\Ax32.exe") -WindowStyle minimized -ArgumentList ($params + " -StartupCmd=CompileAll")
if ($axProcess.WaitForExit($AXCOMPILETIMEOUT) -eq $false)
{
	Throw ("Error: Compile did not complete within " + $AXCOMPILETIMEOUT / 60000 + " minutes")
}

# ********************************************
# **     Convert the Compile Log to XML     **
# ********************************************
"Extract compile log information"
& ($buildSourcePath + "`\AxCompileHTML2XML.ps1") ($logPath + "`\AxCompileAll.html") ($buildSourcePath + "`\CompileLog.xml")

& ($buildSourcePath + "`\ExtractXMLCompileMessages.ps1") ($buildSourcePath + "`\CompileLog.xml") "254,255" | out-string -width 999999

# ********************************************
# **      Copy files to binary folder       **
# ********************************************

# Refresh our object
$aosService.Refresh()
# If it's running, stop the service (DISABLED, NEED TO KEEP RUNNING FOR UNIT TESTS)
#Stop-Service -WarningAction:SilentlyContinue $aosService.Name 


# Copy labels to the application path
& ($buildSourcePath + "`\CopyLabels.ps1") ($buildSourcePath + "`\labels") $BINARIESPATH

Copy-Item ($applicationPath + "`\ax" + $buildLayer + ".aod") $BINARIESPATH
